/*******************************************************************************
 * Copyright (c) 2017 Chen Chao and other ECD project contributors.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/

package jdec.jdt.ls.decompiler.common;

import java.util.Enumeration;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.internal.core.BufferManager;
import jdec.jdt.ls.decompiler.common.util.Logger;

/**
 * This class is a hack that replaces JDT <code>BufferManager</code> in order to
 * make <code>addBuffer()</code> and <code>removeBuffer()</code> accessible.
 */
public class JavaDecompilerBufferManager extends BufferManager {

    public static void closeDecompilerBuffers(boolean all) {
        BufferManager manager = BufferManager.getDefaultBufferManager();
        if (manager instanceof JavaDecompilerBufferManager) {
            Enumeration enumeration = manager.getOpenBuffers();
            while (enumeration.hasMoreElements()) {
                IBuffer buffer = (IBuffer) enumeration.nextElement();
                ((JavaDecompilerBufferManager) manager).removeBuffer(buffer);
            }
        }
    }

    public JavaDecompilerBufferManager(BufferManager manager) {
        synchronized (BufferManager.class) {
            Enumeration enumeration = manager.getOpenBuffers();
            while (enumeration.hasMoreElements()) {
                IBuffer buffer = (IBuffer) enumeration.nextElement();
                addBuffer(buffer);
            }
            BufferManager.DEFAULT_BUFFER_MANAGER = this;
        }
    }

    @Override
    public void addBuffer(final IBuffer buffer) {
        if (buffer == null || buffer.getContents() == null) {
            if (buffer != null) {
                delayAddBuffer(buffer);
            }
            return;
        }

        super.addBuffer(buffer);
    }

    private void delayAddBuffer(final IBuffer buffer) {
        new Thread() {

            @Override
            public void run() {
                if (buffer.getContents() != null) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        Logger.debug(e);
                    }
                    addBuffer(buffer);
                }
            }
        }.start();
    }

    @Override
    public void removeBuffer(IBuffer buffer) {
        super.removeBuffer(buffer);
    }

    @Override
    public IBuffer getBuffer(final IOpenable owner) {
        IBuffer buffer = super.getBuffer(owner);
        if (buffer != null) {
            boolean enableCache = JavaDecompilerPlugin.getDefault().isEnableCache();
            if (!enableCache) {
                removeBuffer(buffer);
                return null;
            }
        }
        return buffer;
    }

    public static JavaDecompilerBufferManager getBufferManager() {
        JavaDecompilerBufferManager manager;
        BufferManager defManager = BufferManager.getDefaultBufferManager();
        if (defManager instanceof JavaDecompilerBufferManager) {
            manager = (JavaDecompilerBufferManager) defManager;
        } else {
            manager = new JavaDecompilerBufferManager(defManager);
        }
        return manager;
    }

}
